package com.yc.cloud.admin.service.impl;

import com.yc.cloud.admin.dto.request.HwCameraCreateReqDTO;
import com.yc.cloud.admin.dto.request.HwCameraUpdateReqDTO;
import com.yc.cloud.admin.dto.request.HwCameraQueryReqDTO;
import com.yc.cloud.admin.dto.request.SipDeviceQueryReqDTO;
import com.yc.cloud.admin.dto.request.CameraStorageStrategyBindReqDTO;
import com.yc.cloud.admin.dto.request.HwCameraStorageRelationCreateReqDTO;
import com.yc.cloud.common.orm.CommonPage;
import com.yc.cloud.common.basic.dto.BasePageReqDTO;
import com.yc.cloud.admin.vo.HwCameraVo;
import com.yc.cloud.admin.vo.SipDeviceListVo;
import com.yc.cloud.admin.vo.SipDeviceVo;
import com.yc.cloud.admin.vo.HwCameraStorageRelationVo;
import com.yc.cloud.admin.vo.CameraBoundStorageStrategyVo;
import com.yc.cloud.entity.HwCamera;
import com.yc.cloud.entity.HwDeviceCamera;
import com.yc.cloud.entity.HwCameraStorageRelation;
import com.yc.cloud.entity.HwCameraStorageStrategy;
import com.yc.cloud.mapper.HwCameraMapper;
import com.yc.cloud.mapper.HwDeviceCameraMapper;
import com.yc.cloud.admin.service.HwCameraService;
import com.yc.cloud.admin.service.SipServerService;
import com.yc.cloud.admin.service.HwCameraStorageRelationService;
import com.yc.cloud.admin.service.HwCameraStorageStrategyService;
import com.yc.cloud.admin.config.StreamProperties;
import com.yc.cloud.admin.utils.StreamUrlBuilder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.cloud.common.basic.exception.Asserts;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 摄像头管理表 服务实现类
 * </p>
 *
 * @author kinggu
 * @since 2025-08-25
 */
@Slf4j
@Service
public class HwCameraServiceImpl extends ServiceImpl<HwCameraMapper, HwCamera> implements HwCameraService {

    @Autowired
    private StreamProperties streamProperties;

    @Autowired
    private HwDeviceCameraMapper hwDeviceCameraMapper;
    
    @Autowired
    private SipServerService sipServerService;
    
    @Autowired
    private HwCameraStorageRelationService hwCameraStorageRelationService;
    
    @Autowired
    private HwCameraStorageStrategyService hwCameraStorageStrategyService;
    
    @Autowired
    private com.yc.cloud.admin.service.HwRegionService hwRegionService;
    
    @Autowired
    private com.yc.cloud.admin.service.HwMonitoringPointService hwMonitoringPointService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HwCameraVo create(HwCameraCreateReqDTO createReqDTO) {
        // SIP用户名唯一性校验
        if (StrUtil.isNotBlank(createReqDTO.getSipUsername())) {
            QueryWrapper<HwCamera> checkWrapper = new QueryWrapper<>();
            checkWrapper.eq(HwCamera.SipUsername, createReqDTO.getSipUsername())
                       .eq(HwCamera.IsDeleted, 0);
            long count = count(checkWrapper);
            if (count > 0) {
                Asserts.fail("SIP用户名已存在，请使用其他用户名");
            }
        }
        
        HwCamera entity = new HwCamera();
        BeanUtils.copyProperties(createReqDTO, entity);
        // 设置默认端口为554
        entity.setCameraPort(554);
        // 构建并设置流地址
        entity.setStreamUrl(buildStreamUrl(entity));
        boolean success = save(entity);
        if (success) {
            return getVOById(entity.getId());
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HwCameraVo update(HwCameraUpdateReqDTO updateReqDTO) {
        // 1. 校验待更新的记录是否存在
        if (getById(updateReqDTO.getId()) == null) {
            Asserts.fail("记录不存在，无法更新");
        }
        
        // 2. SIP用户名唯一性校验（排除当前记录）
        if (StrUtil.isNotBlank(updateReqDTO.getSipUsername())) {
            QueryWrapper<HwCamera> checkWrapper = new QueryWrapper<>();
            checkWrapper.eq(HwCamera.SipUsername, updateReqDTO.getSipUsername())
                       .eq(HwCamera.IsDeleted, 0)
                       .ne(HwCamera.ID, updateReqDTO.getId()); // 排除当前记录
            long count = count(checkWrapper);
            if (count > 0) {
                Asserts.fail("SIP用户名已存在，请使用其他用户名");
            }
        }
        
        HwCamera entity = new HwCamera();
        BeanUtils.copyProperties(updateReqDTO, entity);
        // 重新构建并设置流地址
        entity.setStreamUrl(buildStreamUrl(entity));
        boolean success = updateById(entity);
        if (success) {
            return getVOById(entity.getId());
        }
        return null;
    }

    @Override
    public CommonPage<HwCameraVo> list(HwCameraQueryReqDTO queryReqDTO) {
        QueryWrapper<HwCamera> queryWrapper = new QueryWrapper<>();

        // 分组条件
        if (queryReqDTO.getGroupId() != null) {
            queryWrapper.eq(HwCamera.GroupId, queryReqDTO.getGroupId());
        }
        
        // 区域条件
        if (queryReqDTO.getRegionId() != null) {
            if (Boolean.TRUE.equals(queryReqDTO.getIncludeChildren())) {
                // 包含子区域：查询当前区域及其所有子区域
                List<Long> regionIds = hwRegionService.getChildrenIds(queryReqDTO.getRegionId());
                regionIds.add(queryReqDTO.getRegionId()); // 包含当前区域
                queryWrapper.in(HwCamera.RegionId, regionIds);
            } else {
                // 仅查询当前区域
                queryWrapper.eq(HwCamera.RegionId, queryReqDTO.getRegionId());
            }
        }

        // 关键字查询
        if (StrUtil.isNotEmpty(queryReqDTO.getKeyword())) {
            queryWrapper.and(wrapper -> wrapper.like(HwCamera.Name, queryReqDTO.getKeyword())
                    .or()
                    .like(HwCamera.Location, queryReqDTO.getKeyword())
                    .or()
                    .like(HwCamera.Description, queryReqDTO.getKeyword()));
        }

        // 排序
        if (StrUtil.isNotEmpty(queryReqDTO.getSortBy())) {
            if (Objects.equals(BasePageReqDTO.ORDER_DESC, queryReqDTO.getOrder())) {
                queryWrapper.orderByDesc(StrUtil.toUnderlineCase(queryReqDTO.getSortBy()));
            } else {
                queryWrapper.orderByAsc(StrUtil.toUnderlineCase(queryReqDTO.getSortBy()));
            }
        }

        // 逻辑删除
        queryWrapper.eq(HwCamera.IsDeleted, 0);

        // 根据 page 参数决定是否分页
        if (Boolean.TRUE.equals(queryReqDTO.getPage())) {
            Page<HwCamera> page = new Page<>(queryReqDTO.getPageNum(), queryReqDTO.getPageSize());
            Page<HwCamera> dbPage = baseMapper.selectPage(page, queryWrapper);
            IPage<HwCameraVo> voPage = dbPage.convert(this::convertToVo);
            CommonPage<HwCameraVo> result = CommonPage.restPage(voPage);
            // 同步SIP设备状态
            syncSipDeviceStatus(result.getList());
            return result;
        } else {
            List<HwCamera> allRecords = baseMapper.selectList(queryWrapper);
            CommonPage<HwCameraVo> result = new CommonPage<>();
            List<HwCameraVo> voList = convertToVoList(allRecords);
            result.setList(voList);
            result.setTotal((long) allRecords.size());
            result.setPageNum(1);
            result.setPageSize(allRecords.size());
            result.setTotalPage(1);
            // 同步SIP设备状态
            syncSipDeviceStatus(result.getList());
            return result;
        }
    }

    @Override
    public HwCameraVo getVOById(Long id) {
        HwCamera entity = getById(id);
        return convertToVo(entity);
    }

    @Override
    public List<HwCameraVo> convertToVoList(List<HwCamera> entityList) {
        if (entityList == null) {
            return null;
        }
        return entityList.stream()
                .map(this::convertToVo)
                .collect(Collectors.toList());
    }

    @Override
    public HwCameraVo convertToVo(HwCamera entity) {
        if (entity == null) {
            return null;
        }
        HwCameraVo vo = new HwCameraVo();
        BeanUtils.copyProperties(entity, vo);
        vo.setStreamUrl(buildStreamUrl(entity));
        vo.setRtspUrl(StreamUrlBuilder.buildRtspUrl(entity));
        
        // 填充区域名称
        if (entity.getRegionId() != null) {
            try {
                com.yc.cloud.admin.vo.HwRegionVo region = hwRegionService.getVOById(entity.getRegionId());
                if (region != null) {
                    vo.setRegionName(region.getName());
                }
            } catch (Exception e) {
                log.warn("获取区域名称失败: regionId={}, error={}", entity.getRegionId(), e.getMessage());
            }
        }
        
        // 填充监视点名称
        if (entity.getMonitoringPointId() != null) {
            try {
                com.yc.cloud.admin.vo.HwMonitoringPointVo monitoringPoint = hwMonitoringPointService.getDetail(entity.getMonitoringPointId());
                if (monitoringPoint != null) {
                    vo.setMonitoringPointName(monitoringPoint.getName());
                }
            } catch (Exception e) {
                log.warn("获取监视点名称失败: monitoringPointId={}, error={}", entity.getMonitoringPointId(), e.getMessage());
            }
        }
        
        return vo;
    }

    @Override
    public HwCamera get(Long id) {
        return getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Long id) {
        // 1. 校验待删除的记录是否存在
        if (getById(id) == null) {
            Asserts.fail("记录不存在，无法删除");
        }
        return removeById(id);
    }

    @Override
    public List<HwCameraVo> getByGroupId(Long groupId) {
        List<HwCamera> cameras = baseMapper.selectByGroupId(groupId);
        return convertToVoList(cameras);
    }

    @Override
    public List<HwCameraVo> getUngrouped() {
        List<HwCamera> cameras = baseMapper.selectUngrouped();
        return convertToVoList(cameras);
    }

    @Override
    public Long countByGroupId(Long groupId) {
        return baseMapper.countByGroupId(groupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateAllStreamUrls() {
        List<HwCamera> allCameras = baseMapper.selectList(
                new QueryWrapper<HwCamera>().eq(HwCamera.IsDeleted, 0));

        int updateCount = 0;
        for (HwCamera camera : allCameras) {
            String newStreamUrl = buildStreamUrl(camera);
            if (!Objects.equals(camera.getStreamUrl(), newStreamUrl)) {
                camera.setStreamUrl(newStreamUrl);
                updateById(camera);
                updateCount++;
            }
        }
        return updateCount;
    }

    /**
     * 构建摄像头的 WebRTC 播放地址
     * 规则：{scheme}://{host}:{port}/index/api/webrtc?app=rtp&stream={sipUsername}_{videoChannel}&type=play&originTypeStr=rtp_push
     */
    private String buildStreamUrl(HwCamera entity) {
        if (entity == null) {
            return null;
        }
        if (StrUtil.isAllNotBlank(entity.getSipUsername(), entity.getVideoChannel())
                && StrUtil.isNotBlank(streamProperties.getHost())) {
            String base = String.format("%s://%s:%d%s",
                    StrUtil.blankToDefault(streamProperties.getScheme(), "http"),
                    streamProperties.getHost(),
                    streamProperties.getPort() == null ? 6080 : streamProperties.getPort(),
                    "/index/api/webrtc");
            String stream = entity.getSipUsername() + "_" + entity.getVideoChannel();
            return String.format("%s?app=%s&stream=%s&type=%s&originTypeStr=%s",
                    base,
                    "rtp",
                    stream,
                    "play",
                    "rtp_push");
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean pin(Long id) {
        HwCamera update = new HwCamera();
        update.setId(id);
        update.setPinned(Boolean.TRUE);
        update.setPinnedTime(java.time.LocalDateTime.now());
        return updateById(update);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unpin(Long id) {
        HwCamera update = new HwCamera();
        update.setId(id);
        update.setPinned(Boolean.FALSE);
        update.setPinnedTime(null);
        return updateById(update);
    }

    @Override
    public List<HwCameraVo> getUnboundCameras() {
        // 获取所有已绑定的摄像头ID列表
        List<Long> boundCameraIds = hwDeviceCameraMapper.selectList(new QueryWrapper<>())
                .stream()
                .map(deviceCamera -> deviceCamera.getCameraId())
                .collect(Collectors.toList());

        // 查询未绑定的摄像头
        QueryWrapper<HwCamera> queryWrapper = new QueryWrapper<>();
        if (!boundCameraIds.isEmpty()) {
            queryWrapper.notIn(HwCamera.ID, boundCameraIds);
        }

        List<HwCamera> unboundCameras = this.list(queryWrapper);
        return convertToVoList(unboundCameras);
    }


    /**
     * 同步SIP设备状态
     * 批量获取所有SIP设备状态，然后匹配设置到摄像头列表中
     * 
     * @param cameraVos 摄像头VO列表
     */
    private void syncSipDeviceStatus(List<HwCameraVo> cameraVos) {
        if (cameraVos == null || cameraVos.isEmpty()) {
            return;
        }

        try {
            // 批量获取所有SIP设备状态
            SipDeviceQueryReqDTO sipQuery = new SipDeviceQueryReqDTO();
            sipQuery.setPageNum(1);
            sipQuery.setPageSize(1000); // 设置一个较大的值确保获取所有设备
            
            SipDeviceListVo sipDeviceList = sipServerService.queryDevices(sipQuery);
            
            if (sipDeviceList != null && sipDeviceList.getList() != null) {
                // 构建SIP设备状态映射 Map<sipUsername, onlineStatus>
                Map<String, Integer> sipStatusMap = sipDeviceList.getList().stream()
                    .filter(sipDevice -> StrUtil.isNotBlank(sipDevice.getDeviceId()))
                    .collect(Collectors.toMap(
                        SipDeviceVo::getDeviceId,
                        sipDevice -> sipDevice.getOnLine() != null && sipDevice.getOnLine() ? 1 : 0,
                        (existing, replacement) -> replacement // 如果有重复key，使用新值
                    ));
                
                // 匹配并设置摄像头状态
                for (HwCameraVo cameraVo : cameraVos) {
                    if (StrUtil.isNotBlank(cameraVo.getSipUsername())) {
                        Integer onlineStatus = sipStatusMap.get(cameraVo.getSipUsername());
                        if (onlineStatus != null) {
                            cameraVo.setOnlineStatus(onlineStatus);
                        } else {
                            // 如果在SIP服务器中找不到该设备，默认设置为离线
                            cameraVo.setOnlineStatus(0);
                        }
                    } else {
                        // 如果没有SIP用户名，默认设置为离线
                        cameraVo.setOnlineStatus(0);
                    }
                }
                
                log.debug("同步SIP设备状态完成: 查询到{}个SIP设备，更新{}个摄像头状态", 
                    sipDeviceList.getList().size(), cameraVos.size());
            } else {
                // 如果获取SIP设备列表失败，所有摄像头都设置为离线状态
                log.warn("获取SIP设备列表为空，将所有摄像头状态设置为离线");
                cameraVos.forEach(cameraVo -> cameraVo.setOnlineStatus(0));
            }
        } catch (Exception e) {
            log.error("同步SIP设备状态异常，将所有摄像头状态设置为离线", e);
            // 异常情况下，所有摄像头都设置为离线状态
            cameraVos.forEach(cameraVo -> cameraVo.setOnlineStatus(0));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindStorageStrategy(Long cameraId, CameraStorageStrategyBindReqDTO bindReqDTO) {
        // 1. 校验摄像头是否存在
        HwCamera camera = getById(cameraId);
        if (camera == null) {
            Asserts.fail("摄像头不存在");
        }

        // 2. 先解绑摄像头的所有现有存储策略
        boolean unbindResult = hwCameraStorageRelationService.unbindAllCameraStorageStrategies(cameraId);
        if (!unbindResult) {
            Asserts.fail("解绑现有存储策略失败");
        }

        // 3. 如果策略ID列表为空，则只做清除操作
        if (bindReqDTO.getStrategyIds() == null || bindReqDTO.getStrategyIds().isEmpty()) {
            log.info("摄像头 {} 清除所有存储策略绑定", cameraId);
            return true;
        }

        // 4. 批量绑定新的策略
        boolean allSuccess = true;
        for (Long strategyId : bindReqDTO.getStrategyIds()) {
            HwCameraStorageRelationCreateReqDTO createReqDTO = new HwCameraStorageRelationCreateReqDTO();
            createReqDTO.setCameraId(cameraId);
            createReqDTO.setStrategyId(strategyId);
            boolean result = hwCameraStorageRelationService.bindCameraStorageStrategy(createReqDTO);
            if (!result) {
                allSuccess = false;
                log.error("绑定策略失败 - 摄像头ID: {}, 策略ID: {}", cameraId, strategyId);
            }
        }
        
        return allSuccess;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unbindStorageStrategy(Long cameraId, Long strategyId) {
        // 1. 校验摄像头是否存在
        HwCamera camera = getById(cameraId);
        if (camera == null) {
            Asserts.fail("摄像头不存在");
        }

        // 2. 调用存储关系服务进行解绑
        return hwCameraStorageRelationService.unbindCameraStorageStrategy(cameraId, strategyId);
    }

    @Override
    public List<HwCameraStorageRelationVo> getStorageStrategies(Long cameraId) {
        // 1. 校验摄像头是否存在
        HwCamera camera = getById(cameraId);
        if (camera == null) {
            Asserts.fail("摄像头不存在");
        }

        // 2. 调用存储关系服务获取绑定列表
        return hwCameraStorageRelationService.getRelationsByCameraId(cameraId);
    }

    @Override
    public List<CameraBoundStorageStrategyVo> getCameraBoundStorageStrategies(Long cameraId) {
        // 1. 校验摄像头是否存在
        HwCamera camera = getById(cameraId);
        if (camera == null) {
            Asserts.fail("摄像头不存在");
        }

        // 2. 获取摄像头绑定的存储策略关系列表
        List<HwCameraStorageRelationVo> relations = hwCameraStorageRelationService.getRelationsByCameraId(cameraId);
        
        if (relations == null || relations.isEmpty()) {
            return List.of();
        }

        // 3. 获取所有策略ID
        List<Long> strategyIds = relations.stream()
                .map(HwCameraStorageRelationVo::getStrategyId)
                .collect(Collectors.toList());

        // 4. 批量查询存储策略详情
        List<HwCameraStorageStrategy> strategies = hwCameraStorageStrategyService.listByIds(strategyIds);
        Map<Long, HwCameraStorageStrategy> strategyMap = strategies.stream()
                .collect(Collectors.toMap(HwCameraStorageStrategy::getId, strategy -> strategy));

        // 5. 组装结果
        return relations.stream()
                .map(relation -> {
                    CameraBoundStorageStrategyVo vo = new CameraBoundStorageStrategyVo();
                    vo.setRelationId(relation.getId());
                    vo.setCameraId(relation.getCameraId());
                    vo.setStrategyId(relation.getStrategyId());
                    // 设置策略详情
                    HwCameraStorageStrategy strategy = strategyMap.get(relation.getStrategyId());
                    if (strategy != null) {
                        vo.setStrategyName(strategy.getStrategyName());
                        vo.setDescription(strategy.getDescription());
                        vo.setIsGlobalDefault(strategy.getIsGlobalDefault());
                        vo.setStrategyStatus(strategy.getStatus());
                    }

                    // 策略绑定即生效
                    vo.setIsEffective(true);

                    return vo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<Long> getOnlineCameraIds() {
        // 1. 获取数据库中所有摄像头
        List<HwCamera> cameras = baseMapper.selectList(null);
        
        if (cameras.isEmpty()) {
            log.debug("没有找到摄像头");
            return List.of();
        }
        
        // 2. 获取在线的SIP设备列表
        try {
            SipDeviceQueryReqDTO queryReq = new SipDeviceQueryReqDTO();
            queryReq.setPageNum(1);
            queryReq.setPageSize(1000); // 设置较大的页面大小
            
            SipDeviceListVo sipDeviceList = sipServerService.queryDevices(queryReq);
            
            if (sipDeviceList == null || sipDeviceList.getList() == null || sipDeviceList.getList().isEmpty()) {
                log.warn("没有获取到在线的SIP设备");
                return List.of();
            }
            
            // 3. 构建在线设备ID的Set，提高查找效率
            Set<String> onlineDeviceIds = sipDeviceList.getList().stream()
                .filter(device -> device.getOnLine() != null && device.getOnLine()) // 只要在线的设备
                .map(SipDeviceVo::getDeviceId)
                .collect(Collectors.toSet());
            
            log.debug("在线SIP设备数量: {}", onlineDeviceIds.size());
            
            // 4. 过滤出在线的摄像头
            List<Long> onlineCameraIds = cameras.stream()
                .filter(camera -> StrUtil.isNotBlank(camera.getSipUsername()) && 
                                 onlineDeviceIds.contains(camera.getSipUsername()))
                .map(HwCamera::getId)
                .collect(Collectors.toList());
            
            log.debug("在线摄像头数量: {} / {}", onlineCameraIds.size(), cameras.size());
            return onlineCameraIds;
            
        } catch (Exception e) {
            log.error("获取SIP设备列表异常", e);
            // 发生异常时，返回空列表
            return List.of();
        }
    }


}